package com.forrest.hush_util;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.toolkit.ArrayUtils;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.javassist.*;
import org.apache.ibatis.javassist.bytecode.CodeAttribute;
import org.apache.ibatis.javassist.bytecode.LocalVariableAttribute;
import org.apache.ibatis.javassist.bytecode.MethodInfo;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import java.util.HashMap;
import java.util.Map;

/**
 * @Author duanxincheng
 * @Description 切面工具类
 * @Date 2021/1/6 13:48
 */
@Slf4j
public class AopUtils {

    /**
     * 获取AOP代理的方法的参数名称和参数值
     *
     * @param cls
     * @param className
     * @param methodName
     * @param args
     * @return
     */
    public static StringBuffer getNameAndArgs(Class<?> cls,String className,String methodName,Object[] args){

        StringBuffer sb = new StringBuffer();

        Map<String,Object> nameAndArgs = new HashMap<>();

        try {
            ClassPool classPool = ClassPool.getDefault();
            ClassClassPath classClassPath = new ClassClassPath(cls);
            classPool.insertClassPath(classClassPath);

            CtClass ctClass = classPool.get(className);
            CtMethod ctMethod = ctClass.getDeclaredMethod(methodName);
            MethodInfo methodInfo = ctMethod.getMethodInfo();
            CodeAttribute codeAttribute =methodInfo.getCodeAttribute();
            LocalVariableAttribute localVariableAttribute = (LocalVariableAttribute) codeAttribute.getAttribute(LocalVariableAttribute.tag);
            if(ObjectUtils.isEmpty(localVariableAttribute)){
                //
            }
            int pos = Modifier.isStatic(ctMethod.getModifiers()) ? 0 : 1;
            for(int i = 0;i < ctMethod.getParameterTypes().length;i++){
                nameAndArgs.put(localVariableAttribute.variableName(i + pos),args[i]);
            }
            // nameAndArgs的两种类型，用实体类接收的类似这样：
            // reqParams=com.whoareyou.fido.rest.User@616b9c0e
            // 用Map<String,Object>接收的是这样：menuNo=56473283，遍历这个map区分两种不同，使用不同的取值方式。
            // 根据获取到的值所属的不同类型通过两种不同的方法获取参数

            boolean flag = false;
            if(CollectionUtils.isNotEmpty(nameAndArgs)){
                for(Map.Entry<String,Object> entry : nameAndArgs.entrySet()){
                    if(entry.getValue() instanceof String){
                        flag = true;
                        break;
                    }
                }
            }

            if(flag){
                //从map中获取
                sb.append(JSON.toJSONString(nameAndArgs));
            }else {
                if(ArrayUtils.isNotEmpty(args)){
                    for(Object object : args){
                        if(ObjectUtils.isNotEmpty(object)){
                            if(object instanceof MultipartFile ||
                                object instanceof ServletRequest ||
                                object instanceof ServletResponse){
                                continue;
                            }
                            sb.append(JSON.toJSONString(object));
                        }
                    }
                }
            }
        } catch (NotFoundException e) {
            log.error(e.getMessage());
        }
        return sb;
    }


    /**
     * 获取AOP代理的方法的参数名称和参数值
     *
     * @param cls
     * @param className
     * @param methodName
     * @param args
     * @return
     */
    public static Map<String,Object> getNameAndArgsMap(Class<?> cls,String className,String methodName,Object[] args){

        Map<String,Object> nameAndArgs = new HashMap<>();

        try {
            ClassPool classPool = ClassPool.getDefault();
            ClassClassPath classClassPath = new ClassClassPath(cls);
            classPool.insertClassPath(classClassPath);

            CtClass ctClass = classPool.get(className);
            CtMethod ctMethod = ctClass.getDeclaredMethod(methodName);
            MethodInfo methodInfo = ctMethod.getMethodInfo();
            CodeAttribute codeAttribute =methodInfo.getCodeAttribute();
            LocalVariableAttribute localVariableAttribute = (LocalVariableAttribute) codeAttribute.getAttribute(LocalVariableAttribute.tag);
            if(ObjectUtils.isEmpty(localVariableAttribute)){
                //
            }
            int pos = Modifier.isStatic(ctMethod.getModifiers()) ? 0 : 1;
            for(int i = 0;i < ctMethod.getParameterTypes().length;i++){
                nameAndArgs.put(localVariableAttribute.variableName(i + pos),args[i]);
            }
        } catch (NotFoundException e) {
            log.error(e.getMessage());
        }
        return nameAndArgs;
    }

    /**
     * 获取参数名和值
     *
     * @param joinPoint
     * @return
     */
    public static Map getFieldsName(ProceedingJoinPoint joinPoint) throws ClassNotFoundException, NoSuchMethodException {
        // 参数值
        Object[] args = joinPoint.getArgs();

        Signature signature = joinPoint.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        String[] parameterNames = methodSignature.getParameterNames();

        // 通过map封装参数和参数值
        HashMap<String, Object> paramMap = new HashMap();
        for (int i = 0; i < parameterNames.length; i++) {
            paramMap.put(parameterNames[i], args[i]);
        }
        return paramMap;
    }


}
